package pilegen;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.awt.font.TextAttribute;

public class DrawEnvironnement extends Component {
	
	private static final long serialVersionUID = 1L;
	public Graphics2D graph2d;
    public Environnement env;
    public static int sizeRectX = 200;
    public static int ecartX = 70;
    public static int sizeRectY = 90;
    public static int sizeLineY = 12;
	
	public DrawEnvironnement(Environnement env) {
		super();
		this.env = env;
	}

	public DrawEnvironnement() {
		super();
		this.env = null;
	}
    
	@Override
	public void paint(Graphics g) {
		
		graph2d = (Graphics2D) g;
		graph2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		drawPoignees();
		drawVars();
		drawLinksPoignee();
		drawLinksVars();
		
	}
	
	private void drawPoignees() {
		for(int i = 0; i<env.pile.size();i++){
			graph2d.setColor(Color.CYAN);
			graph2d.fillRect(0,i*16,40,16);
			graph2d.setColor(Color.BLUE);
			graph2d.drawRect(0,i*16,40,16);
			String nomvari = "@"+env.pile.get(i).nom;
			graph2d.setColor(Color.BLACK);
			graph2d.drawString(nomvari, 5, i*16+11);
		}
	}
	
	private void drawVars() {
		/* uniquement les variables dont le type figure parmi les classes presentes dans l'attribut types d'environnement
		 * apparaitront sur le diagramme. Chaque classe aura une colonne dediee aux variables de cette classe */
		ArrayList<Integer> cpt = new ArrayList<Integer>();
		for(int k=0; k<env.types.size(); k++){
			cpt.add(0);
		}
		for(int i = 0; i<env.instances.size();i++){
			Variable var_i = env.instances.get(i);
			int row = 0;
			boolean classeDessinable = false;
			for(int j = 0; j<env.types.size(); j++){
				if(env.types.get(j).getName().equals(var_i.type.getName())){
					row = j;
					classeDessinable = true;
				}
			}
			/* une variable dont le type ne figure pas parmi les classes dans env.types ne sera pas affichee */
			if(classeDessinable){
				graph2d.setColor(Color.BLACK);
				int xdep = (row+1)*sizeRectX+((cpt.get(row))%2)*10;
				int ydep = cpt.get(row)*sizeRectY + 20;
				//int ydep = cpt.get(row)*25*(env.instances.get(i).type.getDeclaredFields().length+1 )+ 40;
				var_i.xaff = xdep;
				var_i.yaff = ydep;
				cpt.set(row, cpt.get(row)+1);
				Field[] allFields = Environnement.getAllFields(var_i.type);
				graph2d.drawRect(xdep, ydep, sizeRectX - ecartX, sizeLineY*(allFields.length+2));
				String nomVar_i = var_i.type.getSimpleName()+" "+var_i.name;
				graph2d.drawString(nomVar_i, xdep+2, ydep+12);
				for(int j=0; j < allFields.length; j++){
					/* affichage de chaque attribut */
					String typeatt = allFields[j].getType().getSimpleName();
					String nomatt = allFields[j].getName();
					String typeAttComplet = allFields[j].getType().getName();
					int modifier = allFields[j].getModifiers();
					String prefix = "";
					if(Modifier.isPublic(modifier)){
						prefix = "+";
					}else if(Modifier.isPrivate(modifier)){
						prefix = "-";
					}else if(Modifier.isProtected(modifier)){
						prefix = "#";
					}
					String suffix = "";
					/* affichage des valeurs des types primitifs */
					if(typeAttComplet.equals("java.lang.Integer") || typeAttComplet.equals("int")){
						Variable valVar = GUI.paint.env.getVariableByName(var_i.name+"."+allFields[j].getName());
						if(valVar!=null && valVar.valeur!=null){
							suffix = " = "+valVar.valeur;
						}
					}else if(typeAttComplet.equals("java.lang.String")){
						Variable valVar = GUI.paint.env.getVariableByName(var_i.name+"."+allFields[j].getName());
						if(valVar!=null && valVar.valeur!=null){
							suffix = " = \""+valVar.valeur+"\"";
						}
					}
					if(Modifier.isStatic(modifier)){
						/* ecrire l'attribut statique souligne */
						Font f = graph2d.getFont();
						Map<TextAttribute, Integer> fontAttributes = new HashMap<TextAttribute, Integer>();
						fontAttributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
						Font fUnderline = f.deriveFont(fontAttributes);
						graph2d.setFont(fUnderline);
					}
					graph2d.drawString(prefix+" "+nomatt+": "+typeatt+suffix, xdep+2, ydep+(j+2)*sizeLineY+7);
					if(Modifier.isStatic(modifier)){
						/* il faut remettre le Font a sa valeur initiale car
						 * il ne faut pas tout ecrire en souligne */
						Font fSouligne = graph2d.getFont();
						Font fSimple = new Font(fSouligne.getName(), Font.PLAIN, fSouligne.getSize());
						graph2d.setFont(fSimple);
					}
				}
			}
		}
	}
	
	private void drawLinksPoignee(){
		for(int i=0; i<this.env.pile.size(); i++){
			if(this.env.pile.get(i).pointeVers!=null){
				String pointname = this.env.pile.get(i).pointeVers.name;
				int rang = 0;
				for(int j=0; j<this.env.instances.size(); j++){
					if(this.env.instances.get(j).name.equals(pointname)){
						rang = j;
					}
				}
				//graph2d.drawLine(41, 8+i*16, this.xdeps.get(rang), this.ydeps.get(rang));
				graph2d.drawLine(41, 8+i*16, this.env.instances.get(rang).xaff, this.env.instances.get(rang).yaff);
			}
		}
	}
	
	private void drawLinksVars() {
		for(int i = 0; i<this.env.instances.size(); i++){
			Variable var_i = this.env.instances.get(i);
			if(this.env.isDrawable(var_i.type.getName())){
				int xdep = var_i.xaff;
				int ydep = var_i.yaff;
				for(int j=0; j<var_i.variablesMeres.size(); j++){
					//Variable varMere = var_i.variablesMeres.get(j);
					Variable varMere = this.env.getVariableByName(var_i.variablesMeres.get(j).name);
					/* si l'on connaissait l'indice de l'attribut, on pourrait dessiner une ligne 
					 * a la meme ordonnee que celle de l'attribut */
					int numatt = 0;
					/* une variable ne peut avoir deux attributs de meme nom
					 * Chaque nom d'attribut est unique donc un test d'egalite sur le nom
					 * suffit pour trouver le rang de l'attribut */
					Field[] allFields = Environnement.getAllFields(varMere.type);
					for(int k=0; k<allFields.length; k++){
						Field attMere_k = allFields[k];
						if(attMere_k.getName().equals(var_i.attributsPeres.get(j))){
							numatt = k;
						}
					}
					int xarr = varMere.xaff + sizeRectX - ecartX;
					int yarr = varMere.yaff + (numatt+2)*sizeLineY;
					graph2d.drawLine(xdep,ydep,xarr,yarr);
				}
			}
		}
	}
	
	@Override
	public Dimension getPreferredSize() {	
		return new Dimension(env.types.size()*(sizeRectX+60), 600);
	}
	
	/*private void drawBackground(Graphics2D g2) {
		g2.setColor(Color.WHITE);
		Dimension size = getPreferredSize();
		g2.fillRect(0, 0, size.width, size.height);
	}	
	*/
}

